/*
 * Ganesa Copyright (C) 2008 Wim Crols <twimpiex@gnx.be>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License Version 3
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

package be.gnx.ganesa.application.model;

import java.io.Serializable;
import java.util.Hashtable;
import java.util.Set;
import java.util.Vector;
import java.util.Map.Entry;

import be.gnx.ganesa.application.event.FeatureChangedEvent;
import be.gnx.ganesa.application.event.FeatureChangedListener;

public abstract class Feature {

  private Serializable identifier;

  private Hashtable<String, String> attributes = new Hashtable<String, String>();

  private Hashtable<Serializable, Feature> partOfFeatures = new Hashtable<Serializable, Feature>();

  public Serializable getIdentifier() {
    return identifier;
  }

  public void setIdentifier(Serializable identifier) {
    this.identifier = identifier;
  }

  public void setAttributes(Hashtable<String, String> attributes) {
    this.attributes = attributes;
  }

  public Set<Entry<String, String>> getAttributes() {
    return attributes.entrySet();
  }

  public String getAttribute(String key) {
    return attributes.get(key);
  }

  public void addAttribute(String key, String value) {
    attributes.put(key, value);
    for (FeatureChangedListener featureChangedListener : featureChangedListeners) {
      featureChangedListener.featureChangedEventhappened(new FeatureChangedEvent(this));
    }
  }

  public Hashtable<Serializable, Feature> getPartOfFeatures() {
    return partOfFeatures;
  }

  public abstract void deleteFeature(Feature feature);

  /* event listeners */
  protected Vector<FeatureChangedListener> featureChangedListeners = new Vector<FeatureChangedListener>();

  public Vector<FeatureChangedListener> getDataChangedListeners() {
    return featureChangedListeners;
  }

  public void addFeatureChangedListener(FeatureChangedListener featureChangedListener) {
    if (featureChangedListener == null) {
      throw new NullPointerException();
    } else {
      featureChangedListeners.add(featureChangedListener);
    }
  }

  public void removeFeatureChangedListener(FeatureChangedListener featureChangedListener) {
    if (featureChangedListener == null) {
      throw new NullPointerException();
    } else {
      featureChangedListeners.remove(featureChangedListener);
    }
  }

  //
  public abstract int getDimension();

  public abstract int getCoordinateDimension();

  public abstract int getSpatialDimension();

  public abstract String getFeautureType();

  public abstract int getSRID();

  public abstract Feature getEnvelope();

  public abstract String asText();

  public abstract byte[] asBinary();

  public abstract boolean isEmpty();

  public abstract boolean isSimple();

  public abstract boolean is3D();

  public abstract boolean isMeasured();

  public abstract Feature getBoundary();

  // query
  public abstract boolean equals(Feature feature);

  public abstract boolean disjoint(Feature feature);

  public abstract boolean intersects(Feature feature);

  public abstract boolean touches(Feature feature);

  public abstract boolean crosses(Feature feature);

  public abstract boolean within(Feature feature);

  public abstract boolean contains(Feature feature);

  public abstract boolean overlaps(Feature feature);

  public abstract boolean relate(Feature feature, String matrix);

  public abstract Feature locateAlong(double mValue);

  public abstract Feature locateBetween(double mStart, double mEnd);

  // analysis
  /*
   * Returns the shortest distance between any two Points in the two geometric
   * objects as calculated in the spatial reference system of this geometric
   * object. Because the geometries are closed, it is possible to find a point
   * on each geometric object involved, such that the distance between these 2
   * points is the returned distance between their geometric objects.
   */
  public abstract double distance(Feature feature);

  public abstract Feature buffer(double distance);

  public abstract Feature convexHull();

  public abstract Feature intersection(Feature feature);

  public abstract Feature union(Feature feature);

  public abstract Feature difference(Feature feature);

  public abstract Feature symDifference(Feature feature);

}
